%module quantlib

#pragma SWIG nowarn=325,317,383,384,389,362,401,509,302,319,402,503

%{
//#include <boost/shared_ptr.hpp>
#include <functional>
#include <ql/settings.hpp>
#include <ql/types.hpp>
#include <ql/time/date.hpp>
#include <ql/time/calendar.hpp>
#include <ql/time/calendars/target.hpp>
#include <ql/time/daycounter.hpp>
#include <ql/time/daycounters/actual365fixed.hpp>
#include <ql/math/distributions/normaldistribution.hpp>
#include <ql/math/matrix.hpp>
#include <ql/methods/montecarlo/sample.hpp>
#include <ql/methods/montecarlo/path.hpp>
#include <ql/methods/montecarlo/multipath.hpp>
#include <ql/methods/montecarlo/pathgenerator.hpp>
#include <ql/methods/montecarlo/multipathgenerator.hpp>
//#include <ql/math/randomnumbers/rngtraits.hpp>
#include <ql/math/randomnumbers/mt19937uniformrng.hpp>
#include <ql/math/randomnumbers/inversecumulativerng.hpp>
#include <ql/math/randomnumbers/boxmullergaussianrng.hpp>
#include <ql/version.hpp>
#include <ql/handle.hpp>
#include <ql/stochasticprocess.hpp>
#include <ql/patterns/observable.hpp>
#include <ql/patterns/lazyobject.hpp>
#include <ql/processes/blackscholesprocess.hpp>
#include <ql/processes/eulerdiscretization.hpp>
#include <ql/processes/stochasticprocessarray.hpp>
#include <ql/processes/hestonprocess.hpp>
#include <ql/termstructure.hpp>
#include <ql/termstructures/yieldtermstructure.hpp>
#include <ql/termstructures/yield/flatforward.hpp>
#include <ql/termstructures/voltermstructure.hpp>
#include <ql/termstructures/volatility/equityfx/blackvoltermstructure.hpp>
#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
#include <ql/termstructures/volatility/equityfx/localvoltermstructure.hpp>
#include <ql/quote.hpp>
#include <ql/timegrid.hpp>
#include <ql/quotes/simplequote.hpp>
#include <ql/utilities/disposable.hpp>
#include <ql/processes/forwardmeasureprocess.hpp>
#include <ql/processes/hullwhiteprocess.hpp>
#include <ql/math/interpolations/extrapolation.hpp>
#include <ql/math/randomnumbers/randomsequencegenerator.hpp>
#include <ql/math/randomnumbers/sobolrsg.hpp>
#include <ql/math/randomnumbers/inversecumulativersg.hpp>
#include <ql/math/distributions/normaldistribution.hpp>
#include <ql/math/distributions/poissondistribution.hpp>
#include <ql/option.hpp>
#include <ql/instruments/oneassetoption.hpp>
#include <ql/instruments/vanillaoption.hpp>
#include <ql/instruments/asianoption.hpp>
#include <ql/payoff.hpp>
#include <ql/instruments/payoffs.hpp>
#include <ql/exercise.hpp>
#include <ql/instrument.hpp>
#include <ql/instruments/averagetype.hpp>
#include <ql/pricingengine.hpp>
#include <ql/pricingengines/vanilla/mceuropeanengine.hpp>
#include <ql/pricingengines/asian/mcdiscreteasianengine.hpp>
#include <ql/pricingengines/asian/mc_discr_arith_av_price.hpp>
#include <qt/processes/generalstochasticprocessarray.hpp>
#include <qt/cudatest.hpp>
#include <qt/math/randomnumbers/gpurandomnumbers.hpp>
#include <qt/math/randomnumbers/gpurandomnumbers/gpumersennetwister.hpp>
#include <qt/methods/montecarlo/gpupathgenerators.hpp>
#include <qt/pricingengines/gpumcengine.hpp>
#include <qt/gpucommon.hpp>
#include <qt/tradingengine.hpp>
#include <qt/tradeorder.hpp>
#include <qt/tradingportfolio.hpp>
#include <qt/tradingstrategies/all.hpp>
#include <qt/utilities/daterateholder.hpp>
//#include <ta_func.h>
using namespace QuantLib;
using QuantLib::Handle;
%}


#define QL_INTEGER int
#define QL_BIG_INTEGER long
#define QL_REAL double

%inline %{
//void testFunc(const boost::shared_ptr<QuantLib::StochasticProcess>& proc, QuantLib::Time, QuantLib::Size, bool){};

void testFunc(const boost::shared_ptr<QuantLib::StochasticProcess>& proc, QuantLib::Time, QuantLib::Size, const QuantLib::InverseCumulativeRsg<QuantLib::RandomSequenceGenerator<QuantLib::MersenneTwisterUniformRng>, QuantLib::InverseCumulativeNormal> & generator, bool){};

	class testVanillaOption {
      public:
        testVanillaOption(const boost::shared_ptr<QuantLib::StrikedTypePayoff>&,
                      const boost::shared_ptr<QuantLib::Exercise>&){};
		QuantLib::Volatility impliedVolatility(
             Real price,
             const boost::shared_ptr<GeneralizedBlackScholesProcess>& process) { return 0.0;};
	};
	
	namespace QuantLib {
		class dummyClass {
		  public:
			dummyClass(
				const boost::shared_ptr<GeneralizedBlackScholesProcess>& process,
				 Size timeSteps,
				 Size timeStepsPerYear,
				 bool brownianBridge,
				 bool antitheticVariate,
				 Size requiredSamples,
				 Real requiredTolerance,
				 Size maxSamples,
				 BigNatural seed)
			{
			QL_REQUIRE(timeSteps != Null<Size>() ||
					   timeStepsPerYear != Null<Size>(),
					   "no time steps provided");
			QL_REQUIRE(timeSteps == Null<Size>() ||
					   timeStepsPerYear == Null<Size>(),
					   "both time steps and time steps per year were provided");
			QL_REQUIRE(timeSteps != 0,
					   "timeSteps must be positive, " << timeSteps <<
					   " not allowed");
			QL_REQUIRE(timeStepsPerYear != 0,
					   "timeStepsPerYear must be positive, " << timeStepsPerYear <<
					   " not allowed");
			}
		};
	}
					  
%}

%inline %{
	Size getNullSize() {return Null<Size>();};
	Real getNullReal() {return Null<Real>();};
	boost::shared_ptr<PricingEngine> castPricingEnginePtr(boost::shared_ptr<QuantLib::MCEuropeanEngine<QuantLib::PseudoRandom> > eng){ return eng; }
	boost::shared_ptr<PricingEngine> castPricingEnginePtr(boost::shared_ptr<QuantLib::MCDiscreteArithmeticAPEngine<QuantLib::PseudoRandom> > eng){ return eng; }
	boost::shared_ptr<PricingEngine> castPricingEnginePtr(boost::shared_ptr<QuantLib::GPUMCEngine<QuantLib::OneAssetOption::arguments, QuantLib::OneAssetOption::results> > eng){ return eng; }
	boost::shared_ptr<PricingEngine> castPricingEnginePtr(boost::shared_ptr<QuantLib::GPUMCEngine<DiscreteAveragingAsianOption::arguments, DiscreteAveragingAsianOption::results> > eng){ return eng; }
%}

%include "boost_shared_ptr.i"
%include "std_map.i"
%include "std_string.i"
%include "std_vector.i"
%shared_ptr(QuantLib::Quote)
%shared_ptr(QuantLib::SimpleQuote)
%shared_ptr(QuantLib::Extrapolator)
%shared_ptr(QuantLib::TermStructure)
%shared_ptr(QuantLib::YieldTermStructure)
%shared_ptr(QuantLib::FlatForward)
%shared_ptr(QuantLib::VolatilityTermStructure)
%shared_ptr(QuantLib::BlackVolTermStructure)
%shared_ptr(QuantLib::BlackConstantVol)
%shared_ptr(QuantLib::BlackVolatilityTermStructure)
%shared_ptr(QuantLib::BlackVarianceTermStructure)
%shared_ptr(QuantLib::StochasticProcess)
%shared_ptr(QuantLib::StochasticProcess1D)
%shared_ptr(QuantLib::StochasticProcessArray)
%shared_ptr(QuantLib::GeneralStochasticProcessArray)
%shared_ptr(QuantLib::GeneralizedBlackScholesProcess)
%shared_ptr(QuantLib::BlackScholesProcess)
%shared_ptr(QuantLib::HestonProcess)
%shared_ptr(QuantLib::BlackProcess)
%shared_ptr(QuantLib::GarmanKohlagenProcess)
%shared_ptr(QuantLib::ForwardMeasureProcess)
%shared_ptr(QuantLib::ForwardMeasureProcess1D)
%shared_ptr(QuantLib::HullWhiteProcess)
%shared_ptr(QuantLib::HullWhiteForwardProcess)
%shared_ptr(QuantLib::BlackScholesMertonProcess)
%shared_ptr(QuantLib::Payoff)
%shared_ptr(QuantLib::TypePayoff)
%shared_ptr(QuantLib::FloatingTypePayoff)
%shared_ptr(QuantLib::StrikedTypePayoff)
%shared_ptr(QuantLib::PlainVanillaPayoff)
%shared_ptr(QuantLib::PercentageStrikePayoff)
%shared_ptr(QuantLib::AssetOrNothingPayoff)
%shared_ptr(QuantLib::CashOrNothingPayoff)
%shared_ptr(QuantLib::NullPayoff)
%shared_ptr(QuantLib::GapPayoff)
%shared_ptr(QuantLib::SuperFundPayoff)
%shared_ptr(QuantLib::SuperSharePayoff)
%shared_ptr(QuantLib::Exercise)
%shared_ptr(QuantLib::AmericanExercise)
%shared_ptr(QuantLib::EuropeanExercise)
%shared_ptr(QuantLib::EarlyExercise)
%shared_ptr(QuantLib::BermudanExercise)
%shared_ptr(QuantLib::MCEuropeanEngine<QuantLib::PseudoRandom>)
%shared_ptr(QuantLib::MCDiscreteArithmeticAPEngine<QuantLib::PseudoRandom>)
%shared_ptr(QuantLib::PricingEngine)
%shared_ptr(QuantLib::GPUMersenneTwisterCreatedOnDevice)
%shared_ptr(QuantLib::GPURandomNumbers)
%shared_ptr(QuantLib::GPURandomNumbersCreatedOnDevice)
%shared_ptr(QuantLib::GPUMCEngine<QuantLib::OneAssetOption::arguments, QuantLib::OneAssetOption::results>)
%shared_ptr(QuantLib::GPUMCEngine<QuantLib::DiscreteAveragingAsianOption::arguments, QuantLib::DiscreteAveragingAsianOption::results>)
%shared_ptr(QuantLib::GPUPathGenerator)
%shared_ptr(QuantLib::GPUInlinePathGenerator)
%shared_ptr(QuantLib::GPUPrePathGenerator)
%shared_ptr(QuantLib::GBMSingleCallOptionGPUPrePathGenerator)
%shared_ptr(QuantLib::GBMSingleAsianOptionGPUPrePathGenerator)
%shared_ptr(QuantLib::AssetData)
%shared_ptr(QuantLib::TradingStrategy)
%shared_ptr(QuantLib::LongStrategy)
// %shared_ptr(SimpleQuote)
// %shared_ptr(Quote)

// %inline %{
// #include <boost/shared_ptr.hpp>
// %}

namespace std {
   %template(IntVector) vector<int>;
   %template(DoubleVector) vector<double>;
   %template(DateVector) vector<QuantLib::Date>;
   %template(StochasticProcessSharedPointerVector) vector<boost::shared_ptr<StochasticProcess> >;
   %template(StringFloatMap) map<std::string, float>;
   %template(TradeOrderVector) vector<QuantLib::TradeOrder>;
   %template(PerformanceVector) vector<QuantLib::Performance>;
}


%{
using QuantLib::Settings;
%}

class Settings {
  private:
    Settings();
  public:
    static Settings& instance();
    %extend {
        Date getEvaluationDate() {
            return self->evaluationDate();
        }
        void setEvaluationDate(const Date& d) {
            self->evaluationDate() = d;
        }

        void includeReferenceDateCashFlows(bool b) {
            self->includeReferenceDateCashFlows() = b;
        }
        void includeTodaysCashFlows(bool b) {
            self->includeTodaysCashFlows() = b;
        }
    }
    #if defined(SWIGPYTHON)
    %pythoncode %{
    evaluationDate = property(getEvaluationDate,setEvaluationDate,None)
    includeReferenceDateCashFlows = property(None,includeReferenceDateCashFlows,None)
    includeTodaysCashFlows = property(None,includeTodaysCashFlows,None)
    %}
    #endif
};

%include "ql/version.hpp"

%include "ql/types.hpp"

%include "ql/instruments/averagetype.hpp"

// %include "ql/patterns/observable.hpp"

// %include "ql/patterns/lazyobject.hpp"

%include "ql/methods/montecarlo/sample.hpp"
%template(SampleReal) QuantLib::Sample<Real>;
%template(SamplePath) QuantLib::Sample<Path>;
%template(SampleMultiPath) QuantLib::Sample<MultiPath>;

%include "ql/handle.hpp"

%include "ql/timegrid.hpp"
%inline %{
	//helper function for custom timegrid
	TimeGrid CreateTimeGridFromVector(const std::vector<double> &v)
	{
		return TimeGrid(v.begin(),v.end());
	};
%}

%include "ql/time/calendar.hpp"

%include "ql/time/calendars/target.hpp"

%include "ql/math/interpolations/extrapolation.hpp"

%include "ql/math/matrix.hpp"
%inline %{
	void FillRowMajorMatrixFromVector(QuantLib::Matrix &M, const std::vector<double> &v)
	{
		int count = 0;
		for (int i=0; i<M.rows(); ++i)
		{
		for (int j=0; j<M.columns(); ++j)
			M[i][j] = v[count++];
		}
	}
%}

%include "ql/termstructure.hpp"

%include "ql/termstructures/yieldtermstructure.hpp"

%include "ql/math/distributions/normaldistribution.hpp"

%include "ql/math/randomnumbers/mt19937uniformrng.hpp"

%include "ql/termstructures/voltermstructure.hpp"

%include "ql/termstructures/volatility/equityfx/blackvoltermstructure.hpp"
%template(BlackVolTermStructureHandle) QuantLib::Handle<QuantLib::BlackVolTermStructure>;


%include "ql/methods/montecarlo/path.hpp"

%include "ql/methods/montecarlo/multipath.hpp"

%include "ql/math/randomnumbers/boxmullergaussianrng.hpp"
%template (MersenneBoxMuller) QuantLib::BoxMullerGaussianRng<MersenneTwisterUniformRng>;

%include "ql/methods/montecarlo/pathgenerator.hpp"
//%template (PseudoGenerator) QuantLib::PathGenerator<PseudoRandom::rsg_type>;
%template (MersenneInverseNormalGenerator) QuantLib::PathGenerator<QuantLib::InverseCumulativeRsg<QuantLib::RandomSequenceGenerator<QuantLib::MersenneTwisterUniformRng>, QuantLib::InverseCumulativeNormal> >;

%include "ql/methods/montecarlo/multipathgenerator.hpp"
%template (MersenneInverseNormalMultiGenerator) QuantLib::MultiPathGenerator<QuantLib::InverseCumulativeRsg<QuantLib::RandomSequenceGenerator<QuantLib::MersenneTwisterUniformRng>, QuantLib::InverseCumulativeNormal> >;

%include "ql/utilities/disposable.hpp"

%include "ql/stochasticprocess.hpp"

%ignore QuantLib::detail;
%include "ql/time/date.hpp"

%include "ql/time/daycounter.hpp"

%include "ql/time/daycounters/actual365fixed.hpp"

%include "ql/termstructures/yield/flatforward.hpp"

%include "ql/quote.hpp"
%template(QuoteHandle) QuantLib::Handle<QuantLib::Quote>;

%include "ql/quotes/simplequote.hpp"
//%template(SimpleQuoteHandle) QuantLib::Handle<QuantLib::SimpleQuote>;

%include "ql/termstructures/volatility/equityfx/blackconstantvol.hpp"


%template(YieldTermStructureHandle) QuantLib::Handle<QuantLib::YieldTermStructure>;



// %inline %{
// boost::shared_ptr<QuantLib::StochasticProcess> CreateBlackScholesMertonProcessPointer(QuantLib::Handle<QuantLib::Quote> x0,
            // QuantLib::Handle<QuantLib::YieldTermStructure> dividendTS,
            // QuantLib::Handle<QuantLib::YieldTermStructure> riskFreeTS,
            // QuantLib::Handle<QuantLib::BlackVolTermStructure> blackVolTS)
	// { return boost::shared_ptr<QuantLib::StochasticProcess>(new QuantLib::BlackScholesMertonProcess(x0, dividendTS, riskFreeTS, blackVolTS));}
// %}
%include "ql/processes/blackscholesprocess.hpp"
//%template(StochasticProcessPointer) boost::shared_ptr<QuantLib::StochasticProcess>;

%include "ql/processes/forwardmeasureprocess.hpp"

%include "ql/processes/hullwhiteprocess.hpp"

%include "ql/processes/hestonprocess.hpp"

%include "ql/processes/stochasticprocessarray.hpp"

%include "qt/processes/generalstochasticprocessarray.hpp"

// %template(MoroInvCumulativeMersenneTwisterGaussianRsg)
    // InverseCumulativeRsg<RandomSequenceGenerator<MersenneTwisterUniformRng>,
                         // MoroInverseCumulativeNormal>;
// 
// template <class URNG, class IC>
// class GenericPseudoRandom
// {
	// public:
		// typedef URNG urng_type;
        // typedef InverseCumulativeRng<urng_type,IC> rng_type;
        // typedef RandomSequenceGenerator<urng_type> ursg_type;
        // typedef InverseCumulativeRsg<ursg_type,IC> rsg_type;
	
		// static rsg_type make_sequence_generator(Size dimension, BigNatural seed) {
            // ursg_type g(dimension, seed);
            // //rsg_type v = (icInstance ? rsg_type(g, *icInstance) : rsg_type(g));;
			// return rsg_type(g);
			// };
		// //static boost::shared_ptr<IC> icInstance;
// };

%inline %{
	using namespace QuantLib;
	using QuantLib::InverseCumulativeRsg;
	template <class URNG, class IC>
	QuantLib::InverseCumulativeRsg<QuantLib::RandomSequenceGenerator<URNG>,IC> getGenericPseudo(QuantLib::Size dimension, QuantLib::BigNatural seed)
	{
		QuantLib::RandomSequenceGenerator<URNG> g(dimension, seed);
		return QuantLib::InverseCumulativeRsg<QuantLib::RandomSequenceGenerator<URNG>,IC>(g);
		//return GenericPseudoRandom<URNG, IC>::make_sequence_generator(dimension,seed);
	};
%}
// //%include "ql/math/randomnumbers/rngtraits.hpp"
//%template(GenericMersenneTwisterInverseNormal) GenericPseudoRandom<QuantLib::RandomSequenceGenerator<QuantLib::MersenneTwisterUniformRng>, QuantLib::InverseCumulativeNormal>;
%include "ql/math/randomnumbers/inversecumulativersg.hpp"
%template(GetGenericMersenneTwisterInverseNormal) getGenericPseudo<QuantLib::MersenneTwisterUniformRng, QuantLib::InverseCumulativeNormal>;
%template(MersenneTwisterInverseNormal) QuantLib::InverseCumulativeRsg<QuantLib::RandomSequenceGenerator<QuantLib::MersenneTwisterUniformRng>,QuantLib::InverseCumulativeNormal>;


// %ignore QuantLib::Option::arguments;
// %ignore QuantLib::Option::setupArguments;
// %include "ql/option.hpp"

// %ignore QuantLib::OneAssetOption::results;
// %include "ql/instruments/oneassetoption.hpp"
// class QuantLib::OneAssetOption::results {
// };

//%include "ql/instruments/vanillaoption.hpp"


// %{
// using QuantLib::Option;
// using QuantLib::VanillaOption;
// %}

namespace QuantLib {
	class Option : public Instrument {
		public:
			Option(const boost::shared_ptr<Payoff>& payoff,
               const boost::shared_ptr<Exercise>& exercise);
			enum Type { Put = -1, Call = 1 };
			virtual bool isExpired() const = 0;
			Real NPV() const;
	};
	
	class OneAssetOption : public Option {
		public:
			OneAssetOption(const boost::shared_ptr<Payoff>&,
                       const boost::shared_ptr<Exercise>&);
			enum Type { Put = -1, Call = 1 };
			bool isExpired() const;
	};
	
	
	class VanillaOption : public OneAssetOption {
		public:
			VanillaOption(const boost::shared_ptr<StrikedTypePayoff>&,
						  const boost::shared_ptr<Exercise>&);
			Volatility impliedVolatility(
				 Real price,
				 const boost::shared_ptr<GeneralizedBlackScholesProcess>& process,
				 Real accuracy = 1.0e-4,
				 Size maxEvaluations = 100,
				 Volatility minVol = 1.0e-7,
				 Volatility maxVol = 4.0) const;
			void setPricingEngine(const boost::shared_ptr<PricingEngine>&);
	};
	
	class DiscreteAveragingAsianOption : public OneAssetOption {
		public:
			DiscreteAveragingAsianOption(Average::Type averageType,
                Real runningAccumulator,
                Size pastFixings,
                const std::vector<Date>& fixingDates,
				const boost::shared_ptr<StrikedTypePayoff>&,
						  const boost::shared_ptr<Exercise>&);
			void setPricingEngine(const boost::shared_ptr<PricingEngine>&);
	};
}

%include "ql/payoff.hpp"

%include "ql/instruments/payoffs.hpp"

%include "ql/exercise.hpp"





%include "ql/pricingengines/vanilla/mceuropeanengine.hpp"
%template(MersenneInverseNormalEuropeanEngine) QuantLib::MCEuropeanEngine<QuantLib::PseudoRandom>;


%include "ql/pricingengines/asian/mc_discr_arith_av_price.hpp"
%template(MersenneInverseNormalAsianArithAvPriceEngine) QuantLib::MCDiscreteArithmeticAPEngine<QuantLib::PseudoRandom>;

%include "ql/pricingengines/asian/mcdiscreteasianengine.hpp"



%include "qt/cudatest.hpp"
%include "qt/math/randomnumbers/gpurandomnumbers.hpp"
%include "qt/math/randomnumbers/gpurandomnumbers/gpumersennetwister.hpp"
%include "qt/methods/montecarlo/gpupathgenerators.hpp"
%include "qt/pricingengines/gpumcengine.hpp"
%include "qt/gpucommon.hpp"

%template(GPUMCEuropeanEngine) QuantLib::GPUMCEngine<QuantLib::OneAssetOption::arguments, QuantLib::OneAssetOption::results >;
%template(GPUMCAsianEngine) QuantLib::GPUMCEngine<QuantLib::DiscreteAveragingAsianOption::arguments, QuantLib::DiscreteAveragingAsianOption::results >;

%include "qt/utilities/daterateholder.hpp"
%include "qt/tradingengine.hpp"
%include "qt/tradingportfolio.hpp"
%include "qt/tradeorder.hpp"
%feature("notabstract") LongStrategy;
%include "qt/tradingstrategies/longstrategy.hpp"

//%include "ta_func.h"